home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 March: Reference Library / Dev.CD Mar 96 RL / Dev.CD Mar 96 RL.toast / Technical Documentation / develop / develop Issue 25 / develop Issue 25 code / C++ exceptions in C / UDebugging.h < prev    next >
Encoding:
Text File  |  1995-09-03  |  8.5 KB  |  261 lines  |  [TEXT/CWIE]

  1. // ===========================================================================
  2. //    UDebugging.h                    ©1994 Metrowerks Inc. All rights reserved.
  3. // ===========================================================================
  4. //
  5. //    Debugging macros and functions
  6. //
  7. //        These debugging macros let you control what happens when you
  8. //        throw an exception or raise a signal. By defining certain
  9. //        compiler symbols and global variables, you can display an alert,
  10. //        break into the low-level debugger, or break into the source-level
  11. //        debugger before an exception is thrown or when a signal is raised.
  12. //
  13. //
  14. //    Throw options
  15. //
  16. //        The macros for throwing exceptions defined in UException.h all
  17. //        eventually invoke the Throw_ macro. For example,
  18. //            ThrowIfOSErr_(err) is defined as if ((err) != 0) Throw_(err)
  19. //
  20. //        This header defines the Throw_ macro. The definition used depends
  21. //        on the setting the the Debug_Throw compiler symbol. If you
  22. //        don't #define Debug_Throw, Throw_ is defined to just call the
  23. //        Throw() function. This creates no extra runtime overhead; the
  24. //        preprocessor does all the work.
  25. //
  26. //        However, if you #define Debug_Throw, the Throw_ macro is defined to
  27. //        check the global variable gDebugThrow to decide what to do before
  28. //        eventually calling Throw(). The value of gDebugThrow may be:
  29. //
  30. //            debugAction_Nothing                do nothing
  31. //            debugAction_Alert                display an Alert box
  32. //            debugAction_LowLevelDebugger    break into MacsBug
  33. //            debugAction_SourceDebugger        break into CodeWarrior Debugger
  34. //
  35. //        The Alert box displays the Exception code, as well as the file
  36. //        name and line number where the Throw_ was made.
  37. //
  38. //        For the low-level debugger, the Exception code is displayed as a
  39. //        string. In MacsBug, the console will display two lines:
  40. //            User Break at <Routine> + <Offset>
  41. //            <Exception Code>
  42. //
  43. //        For the source-level debugger, execution will stop with the
  44. //        "arrow" pointing to line containing the Throw instruction. The
  45. //        Exception code is not displayed. You can check the display of
  46. //        variable values in the source debugger for that information.
  47. //        
  48. //        If you aren't running under the source debugger,
  49. //        debugAction_SourceDebugger will break into the low-level debugger
  50. //        on the PowerPC, but may (will?) crash on the 68K.
  51. //
  52. //        If you don't have a low-level debugger installed, your program will
  53. //        crash (unimplemented trap) if it tries to break into the
  54. //        low-level debugger. 
  55. //
  56. //
  57. //    Signal options
  58. //
  59. //        This header also defines macros for raising Signals. The
  60. //        SignalPStr_(pstr) macro takes a Pascal string argument. The
  61. //        string can be a literal (in double quotes beginning with \p)
  62. //        or a StringPtr (and its variants such as Str255) variable.
  63. //
  64. //        The SignalCStr_(cstr) macro takes a literal C string argument.
  65. //        The string must be a literal (text within double quotes) and
  66. //        can't be a char*. Because the underlying Toolbox routines take
  67. //        Pascal strings, the SignalPStr_ macro is more efficient. So you
  68. //        should always use SignalPStr_ when specifying string literals.
  69. //        The SignalCStr_ macro is used internally because the C preprocessor
  70. //        generates C strings for the # operator in macros.
  71. //
  72. //        The SignalIf_(test) and SignalIfNot_(test) macros each take a
  73. //        boolean condition as an argument, and raise a signal depending
  74. //        on whether the condition is true or false.
  75. //
  76. //        If you don't #define Debug_Signal, the Signal macros do nothing.
  77. //        There is no runtime overhead; the preprocessor substitutes
  78. //        white space for the macros.
  79. //
  80. //        If you #define Debug_Signal, then the macros are defined to check
  81. //        the global variable gDebugSignal to decide what to do. The options
  82. //        are the same as those describe above for gDebugThrow.
  83. //
  84. //
  85. //    Usage Notes
  86. //
  87. //        These debugging utilities do not require PowerPlant. All you need
  88. //        are the UDebugging and UException header (.h) and source (.cp)
  89. //        files (and, of course, the Toolbox and C++ runtime libraries).
  90. //
  91. //        To define debugging options for an entire project, specify a
  92. //        custom header as the Prefix File (in the Language Preferences).
  93. //        In this custom header, you should #include your precompiled
  94. //        header (if you use one), for example:
  95. //
  96. //            #include <MacHeaders68K>
  97. //
  98. //        Then include the following lines:
  99. //
  100. //            #define Debug_Throw
  101. //            #define Debug_Signal
  102. //            #include <UDebugging.h>
  103. //            #include <UException.h>
  104. //
  105. //        Then add any additional declarations that you wish to make.
  106. //
  107. //        Comment out the #define's of Debug_Throw and/or Debug_Signal
  108. //        when you wish to turn off those features.
  109. //
  110. //        By default, gDebugThrow and gDebugSignal are set to
  111. //        debugAction_Nothing. These are runtime global variables, so
  112. //        you can set their values at any point in the program. Usually,
  113. //        you will set their values at the beginning of your main program,
  114. //        but you can set them in other places if you want to use different
  115. //        options in different sections of code.
  116. //
  117. //        Another technique is to change the values of gDebugThrow and/or
  118. //        gDebugSignal from the source-level debugger when you are stopped
  119. //        at a breakpoint. This is the recommended way to use the
  120. //        debugAction_SourceDebugger option. As noted above, using that
  121. //        option when not running under the source debugger can cause a
  122. //        crash on the 68K.
  123.  
  124.  
  125. #pragma once
  126.  
  127. #ifndef __TEXTUTILS__
  128. #include <TextUtils.h>
  129. #endif
  130.  
  131. #ifndef __STRINGS__
  132. #include <Strings.h>
  133. #endif
  134.  
  135.  
  136.     // • Functions for displaying Alert boxes
  137.     
  138. class    UDebugging {
  139. public:
  140.     static void    AlertThrowAt(unsigned char *inError, unsigned char *inFile,
  141.                                 long inLine);
  142.     static void    AlertSignalAt(unsigned char *inTestStr,
  143.                                 unsigned char *inFile, long inLine);
  144. };
  145.  
  146.  
  147.     // • Macros for breaking into the low-level and source debuggers
  148.     // For arcane reasons, the Toolbox routines SysBreak() and Debugger()
  149.     // work oppositely on the PowerPC and 68K.
  150.     
  151.     // You can use these macros to break to the low-level and source
  152.     // debuggers, with or without displaying a (Pascal) string.
  153.  
  154. #ifdef powerc
  155.  
  156. #define    BreakToLowLevelDebugger_()        SysBreak()
  157. #define BreakStrToLowLevelDebugger_(s)    SysBreakStr(s)
  158. #define    BreakToSourceDebugger_()        Debugger()
  159. #define    BreakStrToSourceDebugger_(s)    DebugStr(s)
  160.  
  161. #else // 68K
  162.  
  163. #define    BreakToLowLevelDebugger_()        Debugger()
  164. #define    BreakStrToLowLevelDebugger_(s)    DebugStr(s)
  165. #define    BreakToSourceDebugger_()        SysBreak()
  166. #define    BreakStrToSourceDebugger_(s)    SysBreakStr(s)
  167.  
  168. #endif
  169.  
  170.  
  171.     // • Debugging Actions
  172.  
  173. typedef enum {
  174.     debugAction_Nothing                = 0,
  175.     debugAction_Alert                = 1,
  176.     debugAction_LowLevelDebugger    = 2,
  177.     debugAction_SourceDebugger        = 3
  178. } EDebugAction;
  179.  
  180. extern EDebugAction    gDebugThrow;
  181. extern EDebugAction    gDebugSignal;
  182.  
  183.  
  184.     // • Throw Debugging
  185.     
  186. #ifdef Debug_Throw
  187.  
  188. #define SetDebugThrow_(inAction)    gDebugThrow = inAction
  189.  
  190. #define    Throw_(err)                                                    \
  191.     do {                                                            \
  192.         unsigned char    errStr[16];                                    \
  193.         ::NumToString(err, errStr);                                    \
  194.         if (gDebugThrow == debugAction_Alert) {                        \
  195.             unsigned char    fileStr[] = __FILE__;                    \
  196.             c2pstr((char*) fileStr);                                \
  197.             UDebugging::AlertThrowAt(errStr, fileStr, __LINE__);    \
  198.         } else if (gDebugThrow == debugAction_LowLevelDebugger) {    \
  199.             BreakStrToLowLevelDebugger_(errStr);                    \
  200.         } else if (gDebugThrow == debugAction_SourceDebugger) {        \
  201.             BreakToSourceDebugger_();                                \
  202.         }                                                            \
  203.         throw (ExceptionCode)(err);                                    \
  204.     } while (false)
  205.     
  206. #else
  207.  
  208. #define SetDebugThrow_(inAction)
  209.     
  210. #define Throw_(err)        throw (ExceptionCode)(err)
  211.  
  212. #endif // Debug_Throw
  213.  
  214.  
  215.         // • Signal Debugging
  216.         
  217. #ifdef Debug_Signal
  218.  
  219. #define SetDebugSignal_(inAction)    gDebugSignal = inAction
  220.  
  221. #define SignalPStr_(pstr)                                            \
  222.     do {                                                            \
  223.         if (gDebugSignal == debugAction_Alert) {                    \
  224.             unsigned char    fileStr[] = __FILE__;                    \
  225.             c2pstr((char*) fileStr);                                \
  226.             UDebugging::AlertSignalAt(pstr, fileStr, __LINE__);        \
  227.         } else if (gDebugSignal == debugAction_LowLevelDebugger) {    \
  228.             BreakStrToLowLevelDebugger_(pstr);                        \
  229.         } else if (gDebugSignal == debugAction_SourceDebugger) {    \
  230.             BreakToSourceDebugger_();                                \
  231.         }                                                            \
  232.     } while (false)
  233.  
  234. #define SignalCStr_(cstr)                                            \
  235.     do {                                                            \
  236.         unsigned char sigStr[] = cstr;                                \
  237.         c2pstr((char*) sigStr);                                        \
  238.         SignalPStr_(sigStr);                                        \
  239.     } while (false)
  240.  
  241. #define SignalIf_(test)  \
  242.     do {     \
  243.         if (test) SignalCStr_(#test);   \
  244.     } while (false)
  245.  
  246. #define SignalIfNot_(test)    SignalIf_(!(test))
  247.     
  248.     
  249. #else
  250.  
  251. #define SetDebugSignal_(inAction)
  252.  
  253. #define SignalPStr_(pstr)
  254. #define    SignalCStr_(cstr)
  255. #define SignalIf_(test)
  256. #define SignalIfNot_(test)
  257.  
  258. #endif // Debug_Signal
  259.  
  260. #define Assert_(test)    SignalIfNot_(test)
  261.